//
// SnakesView.m
//
// Matt Pharr- pharr@cs.yale.edu
//

#import "SnakesView.h"
#import <dpsclient/wraps.h>
#import <libc.h>

#define MAX_SNAKES            11
#define BEFORE_REDRAW         1000
#define max(x,y)              ((x) > (y) ? (x) : (y))
#define MIN_X                 (bounds.origin.x)
#define MAX_X                 (bounds.size.width)
#define MIN_Y                 (bounds.origin.y)
#define MAX_Y                 (bounds.size.height)

typedef struct {
    NXPoint position;
    NXPoint move_vector;
    int radius;
    float color;
    float d_color;
    float r,g,b;
} SNAKE;

SNAKE snakes[MAX_SNAKES];

@implementation SnakesView

- oneStep
{
    int i;

    if (++nSteps >= BEFORE_REDRAW) {
	usleep(500000);
	nSteps= 0;
	aliveSnakes= 0;
    }
    if (aliveSnakes == 0) {
        PSsetgray(0.0);
	NXRectFill(&bounds);
    }

    if (((aliveSnakes < nSnakes) && (random() % 30 == 1)) ||
        (aliveSnakes == 0)) {
	snakes[aliveSnakes].position.x= random() % (int)MAX_X;
	snakes[aliveSnakes].position.y= MAX_Y;
	if (random() % 2 == 1)
            snakes[aliveSnakes].move_vector.x= (5 + random () % 10) * (MAX_X / 1100);
	else 
            snakes[aliveSnakes].move_vector.x= (-5 - random () % 10) * (MAX_X / 1100);

	if (random() % 2 == 1)
            snakes[aliveSnakes].d_color= randBetween(0.0,0.04);
	else
            snakes[aliveSnakes].d_color= -1 * randBetween(0.0,0.04);

	snakes[aliveSnakes].move_vector.y= -1 * random() % 15;
	snakes[aliveSnakes].radius= 10 + random() % 30;
	snakes[aliveSnakes].color= randBetween(0.0,1.0);
	snakes[aliveSnakes].r= randBetween(0.0,1.0);
	snakes[aliveSnakes].g= randBetween(0.0,1.0);
	snakes[aliveSnakes].b= randBetween(0.0,1.0);
	++aliveSnakes;
    }

    [self lockFocus];
    for (i= 0; i < aliveSnakes; ++i) {
	PSsetgray(0.0);
	PSarc(snakes[i].position.x, max(snakes[i].position.y, snakes[i].radius+1),
	      snakes[i].radius+1, 0, 360);
	PSstroke();

	snakes[i].color += snakes[i].d_color;
	if (snakes[i].color > 1 || snakes[i].color < 0)
            snakes[i].d_color *= -1;

	if ([Window defaultDepthLimit] == NX_TwoBitGrayDepth) {
	    PSsetgray(snakes[i].color);
	}
	else {
	    PSsetrgbcolor(snakes[i].r, snakes[i].g, snakes[i].b);
	}

	PSarc(snakes[i].position.x, max(snakes[i].position.y, snakes[i].radius),
	      snakes[i].radius, 0, 360);
	PSfill();
    }
    [self unlockFocus];

    for (i= 0; i < aliveSnakes; ++i) {
	snakes[i].position.x += snakes[i].move_vector.x;
	snakes[i].position.y += snakes[i].move_vector.y;
	snakes[i].move_vector.y -= 2;
        /*	snakes[i].move_vector.y *= randBetween(.975,.996); */
        /* a little air resistance... */

	if (snakes[i].position.x - snakes[i].radius < MIN_X) {
	    snakes[i].move_vector.x= random() % 15;
	}
	if (snakes[i].position.x + snakes[i].radius > MAX_X) {
	    snakes[i].move_vector.x= -1 * random() % 15;
	}

	if (snakes[i].position.y < MIN_Y) {
	    snakes[i].position.y= MIN_Y;
	    snakes[i].move_vector.y *= -.9;
	}
    }

    return self;
}


- initFrame:(const NXRect *)frameRect
{
    [super initFrame:frameRect];

    [self inspector:self];

    if (NXGetDefaultValue([NXApp appName], "snakesNumber") == NULL) {
	NXWriteDefault([NXApp appName], "snakesNumber", "6");
	nSnakes= 6;
    }
    else {
	nSnakes= atoi(NXGetDefaultValue([NXApp appName], "snakesNumber"));
    }
    if (nSnakes < 1) nSnakes= 1;

    [nSnakesSlider setIntValue:nSnakes];

    return self;
}


- drawSelf:(const NXRect *)rects :(int)rectCount
{
    if (!rects || !rectCount) {
	return self;
    }

    PSsetgray(0.0);
    NXRectFill(rects);

    return self;
}


- (const char *)windowTitle
{
    return "Snakes";
}


- (BOOL)useBufferedWindow
{
    return YES;
}


- inspector:sender
{
    char buf[MAXPATHLEN];

    if (!inspectorPanel) {
	sprintf(buf,"%s/%s",[(BSThinker()) moduleDirectory:"Snakes"],"Snakes.nib");
	[NXApp loadNibFile:buf owner:self withNames:NO];
    }

    return inspectorPanel;
}


-setNSnakes:sender
{
    char temp[40];
	
    nSnakes= [sender intValue];
    aliveSnakes= 0;

    sprintf(temp, "%d", nSnakes);
    NXWriteDefault([NXApp appName], "snakesNumber", temp);

    return self;
}


@end
